package utils

import (
	"crypto/md5"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"time"
	"woo-server/coms/consts"
)

// 从cookie中得到用户权限菜单
func GetRoleMenuCookie(request *http.Request) error {
	//list := make([]*structs.AdminMenu, 0)
	// 获取指定cookie
	c, err := request.Cookie(cookieKey())
	if err != nil {
		return errors.New(consts.CookieErrorIsNull)
	}
	// 解析cookie内容
	params, err := url.ParseQuery(c.Value)
	if err != nil {
		return errors.New(consts.CookieErrorIsNull)
	}
	// 加密字符
	MenuList := params.Get("MenuList")
	if len(MenuList) == 0 {
		return errors.New(consts.CookieErrorIsNull)
	}
	return nil
}

// 将信息设置到cookie中
func SetRoleMenuCookie(writer http.ResponseWriter, req *http.Request, MenuList string) {
	if len(MenuList) == 0 {
		c := &http.Cookie{
			Name:   cookieKey(),
			Value:  "",
			Path:   "/",
			MaxAge: -1,
		}
		http.SetCookie(writer, c)
		return
	}
	// 当前时间戳
	now := fmt.Sprintf("%d", nowUnix())
	// 当前ip
	ip := ClientIp(req)
	// 加密串
	sign := createCookieSign(1, MenuList, now, ip)
	//参数
	params := url.Values{}
	params.Add("avatar", "111")
	params.Add("MenuList", MenuList)
	//params.Add("roleId", fmt.Sprintf("%d", roleId))
	//params.Add("avatar", avatar)
	//params.Add("username", name)
	params.Add("now", now)
	params.Add("sign", sign)
	c := &http.Cookie{
		Name:  cookieKey(),
		Value: params.Encode(),
		Path:  "/",
	}
	fmt.Printf("SetRoleMenuCookie ip:%s; value:%v", ip, c)
	http.SetCookie(writer, c)
}

// 从cookie中得到信息
func GetLoginCookie(request *http.Request) (uint64, string, uint64, error) {
	// 获取指定cookie
	c, err := request.Cookie(cookieKey())
	if err != nil {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	// 解析cookie内容
	params, err := url.ParseQuery(c.Value)
	if err != nil {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	// 加密字符
	sign := params.Get("sign")
	if len(sign) == 0 {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	// uid
	uid, err := strconv.Atoi(params.Get("uid"))
	if err != nil || uid < 1 {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	// 用户角色ID
	roleId, err := strconv.Atoi(params.Get("roleId"))
	fmt.Println("登录角色ID: ", roleId)
	if err != nil || roleId < 1 {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	// 名称
	name := params.Get("username")
	if len(name) == 0 {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	//// 头像
	//avatar := params.Get("avatar")
	//if len(avatar) == 0 {
	//	return 0, "", "", 0, errors.New(consts.CookieErrorIsNull)
	//}
	// Cookie最长使用时长
	now, err := strconv.Atoi(params.Get("now"))
	if err != nil || nowUnix()-now > cookieTtl() {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	// 当前ip
	ip := ClientIp(request)
	// 校验Sign
	newSign := createCookieSign(uint64(uid), name, fmt.Sprintf("%d", now), ip)
	if newSign != sign {
		return 0, "", 0, errors.New(consts.CookieErrorIsNull)
	}
	return uint64(uid), name, uint64(roleId), nil
}

// 将信息设置到cookie中
func SetLoginCookie(writer http.ResponseWriter, req *http.Request, uid uint64, name string, roleId int) {
	if uid == 0 || len(name) == 0 {
		c := &http.Cookie{
			Name:   cookieKey(),
			Value:  "",
			Path:   "/",
			MaxAge: -1,
		}
		http.SetCookie(writer, c)
		return
	}
	// 当前时间戳
	now := fmt.Sprintf("%d", nowUnix())
	// 当前ip
	ip := ClientIp(req)
	// 加密串
	sign := createCookieSign(uid, name, now, ip)
	//参数
	params := url.Values{}
	params.Add("uid", fmt.Sprintf("%d", uid))
	params.Add("roleId", fmt.Sprintf("%d", roleId))
	params.Add("username", name)
	params.Add("now", now)
	params.Add("sign", sign)
	c := &http.Cookie{
		Name:  cookieKey(),
		Value: params.Encode(),
		Path:  "/",
	}
	fmt.Printf("SetLoginCookie ip:%s; value:%v", ip, c)
	http.SetCookie(writer, c)
}

// 根据登录用户信息生成加密字符串
func createCookieSign(uid uint64, name string, now string, ip string) string {
	str := fmt.Sprintf(
		"uid=%d&username=%s&now=%s&ip=%s&secret=%s",
		uid,
		name,
		now,
		ip,
		cookieSecret(),
	)
	return createSignEncrypt(str)
}

// 不可逆字符
func createSignEncrypt(str string) string {
	str = cookieSecret() + str
	sign := fmt.Sprintf("%x", md5.Sum([]byte(str)))
	return sign
}

// 获取当前时间戳
func nowUnix() int {
	// 时区
	timeLocation, _ := time.LoadLocation(consts.DateLocation)

	// 返回时间戳
	return int(time.Now().In(timeLocation).Unix())
}

// 获取当前IP
func ClientIp(req *http.Request) string {

	// 拆分地址
	host, _, _ := net.SplitHostPort(req.RemoteAddr)

	// IP
	return host
}

// 获取配置
func cookieKey() string {
	return GetConfigValue("cookie.key")
}

// 获取配置
func cookieSecret() string {
	return GetConfigValue("cookie.secret")
}

// 获取配置
func cookieTtl() int {
	now, err := strconv.Atoi(GetConfigValue("cookie.ttl"))
	if err != nil {
		return 0
	}
	return now
}
